package com.wan37.client;

import com.wan37.client.handler.ClientHandler;
import com.wan37.client.handler.ClientHeartbeatHandler;
import com.wan37.protobuf.ParseRegistryMap;
import com.wan37.protobuf.codec.ProtoPacketDecoder;
import com.wan37.protobuf.codec.ProtoPacketEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.concurrent.TimeUnit;

/**
 * @author ly
 */
public class Client {
    private static final Logger logger = LoggerFactory.getLogger(Client.class);
    private static final String gameServerIp = "127.0.0.1";
    private static final int gameServerPort = 9090;
    private static final int clientNum = 1;
    private static Channel channel;
    private static Bootstrap bootstrap;
    public static ClientHandler clientHandler = ClientHandler.getInstance();

    public static void main(String[] args) throws InterruptedException {
        //读取spring
        new ClassPathXmlApplicationContext("logic-spring-config.xml");

        new Client().startClient();
    }

    /**
     * 启动客户端
     */
    private void startClient() throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {

                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        //5秒检查一次read write idle
                        pipeline.addLast("IdleStateHandler", new IdleStateHandler(60,
                                60,
                                60, TimeUnit.SECONDS));
                        //LengthFieldBasedFrameDecoder
                        pipeline.addLast("LengthFieldBasedFrameDecoder",
                                new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,
                                        0,
                                        4,
                                        4,
                                        0));
                        pipeline.addLast("ProtobufPacketDecoder", new ProtoPacketDecoder());        //解码器
                        pipeline.addLast("ClientHeartbeatHandler", new ClientHeartbeatHandler("Client1"));
                        pipeline.addLast("clientHandler", clientHandler);                  //客户端消息处理类
                        pipeline.addLast("ProtobufPacketEncoder", new ProtoPacketEncoder());    //编码器
                    }
                });
        //客户端连接服务器
        doConnect();
        new Order().doOrder();
    }

    /**
     * 连接远程服务器
     */
    public static void doConnect() {
        if (channel != null && channel.isActive()) {
            return;
        }
        ChannelFuture future = bootstrap.connect(gameServerIp, gameServerPort);
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    //返回成功连接后的channel
                    channel = channelFuture.channel();
                    //注册解析器
                    ParseRegistryMap.initRegistry();
                    logger.info("Client1 连接 GateServer 成功...");
                } else {
                    logger.info("Client1 连接 GateServer 失败，10秒后重试。。");
                    //使用eventLoop的线程池执行定时任务
                    channelFuture.channel().eventLoop().schedule(()->{
                        //延迟10s后, 重连
                        doConnect();
                    }, 10, TimeUnit.SECONDS);
                }
            }
        });
    }
}









